#include "Client.h"

#include <sstream>
#include <sys/time.h>

#include <Utils.h>
#include <Constantes.h>
#include <ConfigurationFile.h>
#include <Serializable.h>
#include <FifoEscritura.h>

Client::Client()
: m_ReceptorFifoAbierto(false)
{
	m_Log = Logger::getInstance();
}

Client::~Client()
{
	
}

void Client::joinChiefClientQueue()
{
	// Intento abrir la cola de clientes del jefe para registrarme
	std::string colaClientePathName = ConfigurationFile::getProperty(Properties::COLA_CLIENTE);
	m_ReceptorJefe.crear(colaClientePathName, CreationMode::DEBE_EXISTIR);
}

void Client::createInstructionReceptor()
{
	// Creo un fifo de recepcion donde me notificaran instrucciones
	std::string strPID = Utils::convertIntToStr(getpid());
	m_ReceptorFifoPathName = "/tmp/cliente_" + strPID;
	
	m_Log->debug("CLIENTE >> Creando receptor "+m_ReceptorFifoPathName);
	bool protectAccess = false;
	m_ReceptorFifo.crear(m_ReceptorFifoPathName,CreationMode::NO_DEBE_EXISTIR, protectAccess);
}

void Client::checkInAttQueue()
{
	bool sendResult = false;
	try
	{
		// Creo una estructura con mis datos
		TCliente cliente;
		// Obtengo la probabilidad configurada de ser VIP
		std::string probabilidadSerVip = ConfigurationFile::getProperty(Properties::PROBABILIDAD_VIP);
		// Verifico si debo ser VIP o no
		if(Utils::generateRandNumber(100) < Utils::convertSrtToInt(probabilidadSerVip))
			cliente.mtype = TipoCliente::TIPO_CLIENTE_VIP;
		else
			cliente.mtype = TipoCliente::TIPO_CLIENTE_NORMAL;
		cliente.fifoPathSize = m_ReceptorFifoPathName.size();
		m_ReceptorFifoPathName.copy(cliente.fifoPath, cliente.fifoPathSize);
		
		// Agrego mis datos al fifo del jefe
		sendResult = m_ReceptorJefe.escribir(cliente);
	}
	catch (const BaseException& e)
	{
		std::stringstream eMsg;
		eMsg << "No se pudo registrar en cola de atencion a clientes del jefe.";
		eMsg << e.what() << ". Cliente se retira";
		throw BaseException(eMsg.str(), Client::RETREATE_EXIT);
	}
	if(!sendResult)
		throw BaseException("Ocurrio un error al enviar los datos al jefe", Client::RETREATE_EXIT);
}

std::string Client::retrieveInstructions()
{
	this->abrirReceptorFifo();
	return m_MessageTxRx.obtenerAtributoDeReceptor(m_ReceptorFifo, MessageKey::INSTRUCCION);
}

bool Client::shouldLeave(const std::string& instruction) const
{
	return (instruction.compare(InstructionValue::FINALIZAR) == 0);
}

bool Client::hasBeenAssisted(const std::string& instruction) const
{
	return (instruction.compare(InstructionValue::DAME_MONTO) == 0);
}

void Client::askForGas(int amount)
{
	std::string amountStr = Utils::convertIntToStr(amount);
	
	// Obtengo datos del empleado que me atendio
	std::string employeeFifoPath = m_MessageTxRx.obtenerAtributoDeReceptor(m_ReceptorFifo, MessageKey::PATH_FIFO);
	
	// Envio el monto requerido al fifo del playero
	bool protectAccess = true;
	FifoEscritura receptorPlayero(employeeFifoPath, CreationMode::DEBE_EXISTIR, protectAccess);
	receptorPlayero.abrir();
	m_MessageTxRx.enviarAtributoAReceptor(receptorPlayero, MessageKey::TOMA_MONTO, amountStr);
	receptorPlayero.cerrar();
}

void Client::abrirReceptorFifo()
{
	if(!m_ReceptorFifoAbierto)
	{
		m_Log->debug("CLIENTE >> Abriendo FIFO receptor de instrucciones");
		m_ReceptorFifo.abrir();
		m_ReceptorFifoAbierto = true;
	}
}
